package com.jerome.fs.test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class BuildMakeFile {
    static String makefilestr ="# weather file system\n" +
            "# Author: jerome\n" +
            "# create: 2023-09-09\n" +
            "# update: 2023-09-09\n" +
            "# version: 1.0\n" +
            "\n" +
            "# Set the file name of your jar package:\n" +
            "JAR_PKG = {jarPkg}\n" +
            "# Set your entry point of your java app:\n" +
            "ENTRY_POINT = {entryPoint}\n" +
            "# Do you need the res directory? If your program has pictures, documents, etc.,\n" +
            "# It is best to put it in the res directory.\n" +
            "# yes: required; no: not required\n" +
            "RES_DIR = no\n" +
            "\n" +
            "SOURCE_FILES = \\\n" +
            "{javaList}"+
            "\n" +
            "# Set your java compiler here:\n" +
            "JAVAC = javac\n" +
            "\n" +
            "JFLAGS = -encoding UTF-8\n" +
            "\n" +
            "# make build: Compile and generate java classes in the bin directory.\n" +
            "# make clean: Clean up the compilation results for recompilation\n" +
            "# make rebuild: Clean up the compilation results and recompile.\n" +
            "# make run: After make, you can view the running results through make run.\n" +
            "# make jar: Generate an executable jar package.\n" +
            "\n" +
            "#############下面的内容建议不要修改####################\n" +
            "\n" +
            "vpath %.class bin\n" +
            "vpath %.java src\n" +
            "\n" +
            "# show help message by default\n" +
            "Default:\n" +
            "\t@echo \"make new: new project, create src, bin, res dirs.\"\n" +
            "\t@echo \"make build: build project.\"\n" +
            "\t@echo \"make clean: clear classes generated.\"\n" +
            "\t@echo \"make rebuild: rebuild project.\"\n" +
            "\t@echo \"make run: run your app.\"\n" +
            "\t@echo \"make jar: package your project into a executable jar.\"\n" +
            "\n" +
            "build:\n" +
            "\t$(JAVAC) -cp bin -d bin $(JFLAGS) $(SOURCE_FILES)" +
            "\n" +
            "rebuild: clean build\n" +
            "\n" +
            ".PHONY: new clean run jar\n" +
            "\n" +
            "new:\n" +
            "ifeq ($(RES_DIR),yes)\n" +
            "\tmkdir -pv src bin res\n" +
            "else\n" +
            "\tmkdir -pv src bin\n" +
            "endif\n" +
            "\n" +
            "clean:\n" +
            "\trm -frv bin/*\n" +
            "\n" +
            "run:\n" +
            "\tjava -cp bin $(ENTRY_POINT)\n" +
            "\n" +
            "jar:\n" +
            "ifeq ($(RES_DIR),yes)\n" +
            "\tjar cvfe $(JAR_PKG) $(ENTRY_POINT)  -C bin . res\n" +
            "else\n" +
            "\tjar cvfe $(JAR_PKG) $(ENTRY_POINT) -C bin .\n" +
            "endif\n";
    static String projectFolder;
    public static void main(String[] args) throws IOException {
        projectFolder = "D:\\workspace\\studysource\\work2\\src\\main\\java\\";
        List<String> allJavaFiles = new ArrayList<>();
        Map<String, Set<String>> fileDependencies = new HashMap<>();

        // Step 1: Find all Java files in the project folder
        findAllJavaFiles(projectFolder, allJavaFiles);
        // Step 2: Analyze import statements to determine file dependencies
        analyzeFileDependencies(allJavaFiles, fileDependencies);

        // Step 3: Sort Java files based on their dependencies
        List<String> sortedFiles = topologicalSort(fileDependencies);

        // Print the sorted files
//        for (String fileName : sortedFiles) {
//            System.out.println(fileName);
//        }
        BufferedWriter writer = new BufferedWriter(new FileWriter("../Makefile"));
        writer.write(makefilestr.replace("{jarPkg}","work2.jar")
                .replace("{entryPoint}","com.jerome.fs.server.aggregation.AggregationServer")
                .replace("{javaList}",sortedFiles.stream().map(x->{
                    return ("src/main/java/"+x).replace("\\","/")+" \\";
                }).collect(Collectors.joining("\n"))));
        writer.close();

    }

    private static void findAllJavaFiles(String folderPath, List<String> javaFiles) {
        File folder = new File(folderPath);
        File[] files = folder.listFiles();

        if (files != null) {
            for (File file : files) {
                if (file.isFile() && file.getName().endsWith(".java")) {
                    javaFiles.add(folderPath+"/"+file.getName());
                } else if (file.isDirectory()) {
                    findAllJavaFiles(file.getAbsolutePath(), javaFiles);
                }
            }
        }
    }
    static Pattern pattern = Pattern.compile("import +(com.jerome.fs.*);", Pattern.CASE_INSENSITIVE);

    private static void analyzeFileDependencies(List<String> javaFiles, Map<String, Set<String>> dependencies) {
        for (String fileName : javaFiles) {
            Set<String> set = new HashSet<>();
            try (BufferedReader in = new BufferedReader(new FileReader(fileName))) {
                String str;
                while ((str = in.readLine()) != null) {
                    Matcher matcher = pattern.matcher(str);
                    if (matcher.find()) {
                        set.add(matcher.group(1).replace(".","/")+".java");
                    }
                }
                dependencies.put(fileName.replace(projectFolder,"").replace("\\","/"), set);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static List<String> topologicalSort(Map<String, Set<String>> dependencies) {
        // Implement a topological sort algorithm to sort files based on dependencies
        // Return a list of sorted file names
        List<String> list = new ArrayList<>();
        for (String key : dependencies.keySet()) {
            Set<String> keys = new HashSet<>();
            keys.add(key);
            list.addAll(getClassALlDependencies(keys,dependencies,key));
            list.add(key);
        }
        return list.stream().distinct().collect(Collectors.toList());
    }
    /**
     *
     * @author Jerome
     * @date 2023/9/13 14:57
     */
    private static List<String> getClassALlDependencies(Set<String> keys, Map<String, Set<String>> dependencies, String key){
        List<String> list = new ArrayList<>();
        Set<String> strings = dependencies.get(key);
        for (String string : strings) {
            if (keys.add(string)){
                list.addAll(getClassALlDependencies(keys,dependencies,string));
            }
            list.add(string);
        }
        return list;
    }

}
